<template>
    <component v-bind="!isDesign
                ? {is:'el-row'}
                : {is:'Draggable',tag:'el-row',list:components,group:{name:'notNull'},animation:200,emptyInsertThreshold:36}">
        <el-col v-for="(item,index) in components" :key="index" class="dynamic-form-item-wrapper"
                @click.native.stop="!isDesign ? null : desForm.$emit('active-change',item)"
                v-bind="getElColProps(item)">
            <component :is="item.block ? 'el-col' : 'div'" :span="item.size">
                <!-- render -->
                <HighElFormItem v-if="item.render" v-bind="getFormItemProps(item)">
                    <HighRender v-model="model[item.model]" :render="item.render"/>
                </HighElFormItem>

                <!-- 根据type生成 -->
                <HighElFormItem v-else-if="item.component"
                                v-bind="getFormItemProps(item)">
                    <dynamic-item v-model="model[item.model]" :config="item.component"/>
                    <p v-if="item.tip" class="suggest">{{item.tip}}</p>
                </HighElFormItem>

                <!-- 递归，组数据 -->
                <HighElFormItem class="dynamic-form-item-group-wrapper" v-else-if="item.fields"
                                v-bind="getFormItemProps(item)">
                    <p v-if="item.tip" class="suggest">{{item.tip}}</p>
                    <DynamicComponentsRender v-bind="getFormItemGroupProps(item)" class="dynamic-form-item-group"/>
                </HighElFormItem>

                <!-- template，即slot -->
                <HighElFormItem v-bind="getBaseFormItemProps(item)" v-else-if="item.template">
                    <SlotRender v-model="model[item.model]" :name="item.model"/>
                </HighElFormItem>

                <!-- 其它情况，暂未设置 -->
                <HighElFormItem v-else v-bind="getBaseFormItemProps(item)">
                </HighElFormItem>
            </component>
        </el-col>
    </component>
</template>

<script>
    import {HighElFormItem, SlotRender} from './hoc'
    import {HighRender} from './hoc'
    import DynamicItem from './DynamicItem'

    export default {
        name: 'DynamicComponentsRender',
        components: {
            Draggable: () => import('vuedraggable'),
            HighElFormItem,
            HighRender,
            DynamicItem,
            SlotRender,
        },
        inject: {
            dForm: 'dForm',
            desForm: {
                from: 'desForm',
                default: () => null
            },
        },
        props: {
            components: Array,
            model: {
                required: true,
                type: Object,
            },
        },
        data() {
            this.isDesign = this.dForm.design
            return {}
        },
        methods: {
            getElColProps(item) {
                const base = {
                    span: !item.block ? item.size : 24,
                }

                if (this.isDesign) {
                    base['class'] = {
                        active: this.desForm.activeField === item,
                    }
                }
                return base
            },
            getFormItemGroupProps(item) {
                let {model, model: curModel} = this

                if (item.scope) {
                    curModel = {}
                    this.$set(model, item.model, curModel)
                } else {
                    this.$delete(model, item.model) // fix design模式
                }

                let curChild = null
                for (let k in item.fields) {
                    curChild = item.fields[k]
                    if (!curChild.model || curChild.fields) continue
                    // 渲染函数、或者其他的
                    this.$set(curModel, curChild.model, !curChild.component ? undefined : this.dForm.getDefaultModelValueByConfig(curChild.component))
                }

                const base = {
                    model: curModel,
                    components: item.fields,
                }
                return base
            },
            getFormItemClass(item) {
                const classNames = []
                if (!item.label) {
                    classNames.push('label-none')
                }

                if (item.tip) {
                    classNames.push(item.fields ? 'suggest-item-group' : 'suggest-item')
                }
                return classNames
            },
            getBaseFormItemProps(item) {
                return {
                    class: this.getFormItemClass(item),
                    label: item.label,
                    required: item.required, // 如果为false，以rules为准
                }
            },
            getFormItemProps(item) {
                const opts = this.getBaseFormItemProps(item)

                // rules推荐使用数组，方便处理
                if (!this.isDesign) { // 设计模式不需要
                    if (item.model) {
                        // 生成默认rules提示
                        if (item.required || item.rules) {
                            if (!item.rules) {
                                item.rules = [{
                                    required: true,
                                    message: '请完善' + (item.label || '此项目'),
                                }]
                            } else {
                                const allRules = Array.isArray(item.rules) ? item.rules : [item.rules]
                                allRules.forEach(rule => {
                                    // 生成默认rules提示
                                    if (rule.validator) {
                                        rule.validator = rule.validator.bind(this.dForm)
                                    } else {
                                        !rule.message && (rule.message = '请完善' + item.label)
                                    }
                                })
                            }
                        }

                        // 内置验证器
                        if (item.validator) {
                            const {nativeRules} = this.dForm.sys
                            // 暂时只有字符串，其它的情况用rules更好
                            if (typeof item.validator === 'string' && nativeRules[item.validator]) {
                                item.rules.unshift(nativeRules[item.validator]) // 使用unshift，保证错误消息显示顺序
                            }
                        }

                        Object.assign(opts, {
                            prop: item.model,
                            rules: item.rules,
                        })
                    }
                }
                return opts
            },
        },
    }
</script>

<style lang="scss" scoped>
    /deep/ {
        .suggest {
            line-height: 1;
            color: #909399;
            font-size: 12px;
        }

        .suggest-item-group {
            .suggest {
                padding: 11px 0; // 在10 12 之间
            }
        }

        .suggest-item {
            &.is-error {
                .el-form-item__content .suggest {
                    /*display: none;*/
                    margin-top: -22px;
                    white-space: nowrap;
                }
            }

            .el-form-item__content {
                .suggest {
                    @extend .suggest;
                    pointer-events: none;
                    position: absolute;
                    top: 100%;
                    left: 0;
                    padding-top: 4px;
                }
            }
        }
    }
</style>
